package top.byteio.common.core.crypto;



import top.byteio.common.core.utils.CommonUtils;

import java.security.MessageDigest;

/**
 * Message Digest algorithm 5，信息摘要算法，MD5
 * <b>一般用于确保信息的传输完整一致性，校验传输的数据是否被修改，一旦原始信息被修改，生成的 MD5 值将会变得很不同</b>
 * <ul>
 *   <li>算法能将任意大小、格式的文字或文件进行加密从而产生 128 bit（16 字节）的散列值。如同人的指纹，不同文本的 MD5 值是不同的。</li>
 *   <li>极端情况：就是不同的字符串的 MD5 值一样，这叫哈希碰撞。2009 年中科院就已经实现了相应的碰撞算法，不过 MD5 应用仍然很广泛</li>
 *   <li>一般不可破解，除非使用穷举法，难度依旧很大</li>
 * </ul>
 *
 * @author lerry
 * @since 2023/6/21 1:22
 */
public class MD5 implements ICrypt {

    private static final String MD5_ALGORITHM = "MD5";


    /**
     * 将字符串进行MD5加密
     *
     * @param str 待加密的字符串
     * @return String 加密后的字符串
     * @author lerry
     */
    public static String encode(String str) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance(MD5_ALGORITHM);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }

        char[] charArray = str.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++) {
            byteArray[i] = (byte) charArray[i];
        }

        byte[] md5Bytes = md5.digest(byteArray);

        StringBuilder hexValue = new StringBuilder();

        for (byte md5Byte : md5Bytes) {
            int val = ((int) md5Byte) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }

        return hexValue.toString();
    }


    /**
     * 加盐加密
     *
     * @param password 待加密的密码
     * @param salt     盐值
     * @return java.lang.String 加盐加密后的字符串
     * @author lerry
     * @since 2023/5/21 13:45
     */
    public static String encodeBySalt(String password, String salt) {
        password = password + salt;
        return encode(password);
    }


    /**
     * 生成随机盐值
     *
     * @param length 盐值的长度
     * @return java.lang.String 随机盐值
     * @author lerry
     * @since 2023/5/21 13:44
     */
    public static String generateSalt(int length) {
        char[] chars = CommonUtils.generateRandomCharacters(length, true);
        return new String(chars);
    }

    /**
     * 验证字符串是否匹配MD5加密后的结果
     *
     * @param str    待验证的字符串
     * @param md5Str MD5加密后的结果
     * @return boolean true 验证成功，false 验证失败
     * @author lerry
     */
    public static boolean validate(String str, String md5Str) {
        return md5Str.equals(encode(str));
    }
}
